/**************************************************************************************************
*******
**************************************************************************************************/


#include "bus_dev.h"
#include "gpio.h"
#include "clock.h"
#include "i2c_s.h"
#include "i2c.h"
#include "error.h"
#include "log.h"

typedef struct{
  uint8_t           id;  //0: uninit, 1: i2c0, 2:i2c1
  uint8_t           mode; //(1)I2CS_MODE_REG_8BIT,  (2)I2CS_MODE_REG_16BIT,(3)I2CS_MODE_RAW
  uint8_t           saddr;
  gpio_pin_e        cs;  //cs pin, used to  wakeup or release
  gpio_pin_e        sda;
  gpio_pin_e        scl;
  AP_I2C_TypeDef*   dev;
  i2cs_hdl_t        evt_handler;
  uint8_t           rxoffset;
  uint8_t           rxbuf[I2CS_RX_MAX_SIZE];
  uint8_t           txoffset;
  uint8_t           txbuf[I2CS_TX_MAX_SIZE];
}i2cs_ctx_t;

static uint8_t s_i2cs_state = I2CSST_IDLE;

static i2cs_ctx_t s_i2cs_ctx;

static void i2cs_irq_rx_handler(AP_I2C_TypeDef* pdev)
{
  uint32_t val;
	while(1){
		if((pdev->IC_STATUS & BV(3)) == 0)
		  break;
		val = pdev->IC_DATA_CMD;
		LOG("Rx %x\n",val);
	}
}
static uint32_t tx_dummy = 0; 
static void i2cs_irq_tx_handler(AP_I2C_TypeDef* pdev)
{
  pdev->IC_DATA_CMD = tx_dummy &0xff;
	tx_dummy ++;
  pdev->IC_DATA_CMD = tx_dummy &0xff;
	tx_dummy ++;
  //LOG("Tx\n");
}
static void i2cs_irq_handler(AP_I2C_TypeDef* pdev)
{
  uint32_t int_status = pdev->IC_INTR_STAT;
	uint32_t clr = pdev->IC_CLR_INTR;
	//LOG("i2cs_irq_handler %x\n",int_status);
	if(int_status & I2C_MASK_START_DET)
	{
	  
	}
  if(int_status & I2C_MASK_RX_FULL)
  {
    i2cs_irq_rx_handler(pdev);
  }
  if(int_status & I2C_MASK_RD_REQ)
  {
    i2cs_irq_tx_handler(pdev);

  }
}

void __attribute__((used)) hal_I2C0_IRQHandler(void)
{
  i2cs_ctx_t* pctx = &s_i2cs_ctx;
  if(pctx->id == I2CS_0)
    i2cs_irq_handler(AP_I2C0);
}
void __attribute__((used)) hal_I2C1_IRQHandler(void)
{
  i2cs_ctx_t* pctx = &s_i2cs_ctx;
  if(pctx->id == I2CS_1)
    i2cs_irq_handler(AP_I2C1);
}



int i2cs_init(
  i2cs_channel_t  ch_id,
  i2cs_mode_t     mode,
  uint8_t         saddr,  //slave address
  gpio_pin_e      cs,  //if need not cs, choose GPIO_DUMMY_PIN
  gpio_pin_e      sda,
  gpio_pin_e      scl,
  i2cs_hdl_t      evt_handler)
{
  i2cs_ctx_t* pctx = &s_i2cs_ctx;
  Fmux_Type_e   fmux;
  MODULE_e      module;
  AP_I2C_TypeDef* pdev = NULL;
  int    irqid;
  if(pctx->id){
    return PPlus_ERR_IO_CONFILCT;
  }

  //parameter validate check


  //set device
  irqid = (ch_id == I2CS_0) ? I2C0_IRQ : I2C1_IRQ;
  module = (ch_id == I2CS_0) ? MOD_I2C0 : MOD_I2C1;
  hal_clk_gate_enable(module);
  
  pdev = (ch_id == I2CS_0) ? AP_I2C0 : AP_I2C1;
	pctx->id = ch_id;
  pctx->dev = pdev;
  pctx->saddr = saddr;
  pctx->cs = cs;
  pctx->scl = scl;
  pctx->sda = sda;
  pctx->evt_handler = evt_handler;
  
  fmux = (ch_id == I2CS_0) ? IIC0_SCL : IIC1_SCL;
  hal_gpio_fmux_set(scl, fmux);
  
  fmux = (ch_id == I2CS_0) ? IIC0_SDA : IIC1_SDA;
  hal_gpio_fmux_set(sda, fmux);
  
  hal_gpio_pull_set(scl , STRONG_PULL_UP);
  hal_gpio_pull_set(sda , STRONG_PULL_UP);

  pdev->IC_ENABLE = 0; //disable
  pdev->IC_CON = (SPEED_FAST) << 1;
  pdev->IC_SAR = saddr;
  pdev->IC_RX_TL = 1;
  pdev->IC_TX_TL = 1;
  pdev->IC_INTR_MASK = 0xfef;//(I2C_MASK_TX_ABRT | I2C_MASK_RD_REQ | I2C_MASK_RX_FULL | I2C_MASK_RX_DONE);

  pdev->IC_ENABLE = 1; //disable

  NVIC_EnableIRQ((IRQn_Type)irqid);
		
  NVIC_SetPriority(irqid, IRQ_PRIO_HAL);
  
  return PPlus_SUCCESS;
}


int i2cs_deinit(void)
{
  i2cs_ctx_t* pctx = &s_i2cs_ctx;
  if(pctx->id == 0)
    return PPlus_ERR_IO_FAIL;

  //release io
	
	return PPlus_SUCCESS;
}

